package study.spring.core.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.time.LocalTime;

@Component
@Aspect
public class AspectBean {
  protected final Logger log = LoggerFactory.getLogger(getClass());

  /*
  定义一个 point cut 表达式,
      可以用 @Pointcut(value= execution 或  within 或 this 或 target 或 args, )
      也可在 @After、@Before、@Around 中可以直接写表达式

  execution 和 within 的区别:
      execution 可以定义到 方法名, 方法的参数, 方法的返回值
      within    只能定义到 类

  因为是切入的是 Class, spring会使用 Cglib 增强, 增强后的类与 CglibAopProxy 有关
  */
  @Pointcut(value = "execution(public * study.spring.core.aop.TargetObject.joinPoint(..))")
  public void pointCut() {

  }

  /* 在切面中取参数的写法 */
  @Around(value = "execution(public int study.spring.core.aop.TargetObject.joinPoint2(..)) && args(a, b)", argNames = "pjp,a,b")
  public Object doBasicProfiling(ProceedingJoinPoint pjp, String a, LocalTime b) throws Throwable {
    // start stopwatch
    log.info("这里是环绕通知 around advice exe before");
    log.info("取到的参数是: "+ a+" "+b);
    Object[] args = pjp.getArgs();
    Object retVal = pjp.proceed(new Object[]{"在切面中使用ProceedingJoinPoint.proceed()传递的参数", b});
//    log.info("around advice get value:{}", retVal);
    // stop stopwatch
    return retVal;
  }

  // @After、@Before、@Around 中可以直接写表达式, 也可以指向一个 @Pointcut 修饰的方法
  @Before("pointCut()")
  public void before() {
    log.info("前置通知执行 before advise");
  }

  @After(value = "within(study.spring.core.aop.TargetObject)")
  public void after() {
    log.info("后置通知执行  after advise (在TargetObject类的所有方法切入)");
  }

  @Before(value = "execution(public * study.spring.core.aop.TargetObjectPrototype.singletonAspectUse(..))")
  public void recordServiceUsage() {
    log.info("这是一个 单例aspect bean在执行, 它的hashcode: " + this.hashCode());
  }

}
